﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Pointandclick.Animation
{
    enum Direction { Horizontal, Vertical };

    class AnimatedSprite
    {
        bool playing = false;
        Texture2D spriteSheet;
        int fps;
        Rectangle frame;
        Direction direction;
        float elapsedTime;
        bool playOnce;

        #region Constructors

        /// <summary>
        /// Sprite that supports unidimensional sprite sheets
        /// </summary>
        /// <param name="spriteSheet">Image with all the frames</param>
        /// <param name="fps">Frames per second</param>
        /// <param name="frame">Rectangle with the frame's height and width</param>
        public AnimatedSprite(Texture2D spriteSheet, int fps, Rectangle frame)
        {
            this.spriteSheet = spriteSheet;
            this.fps = fps;
            this.frame = new Rectangle(0, 0, frame.Width, frame.Height);
            if (frame.Width == spriteSheet.Width)
                direction = Direction.Vertical;
            else if (frame.Height == spriteSheet.Height)
                direction = Direction.Horizontal;
            else
                throw (new InvalidFrameException());

        }

        /// <summary>
        /// Sprite that supports unidimensional sprite sheets
        /// </summary>
        /// <param name="spriteSheet">Image with all the frames</param>
        /// <param name="fps">Frames per second</param>
        /// <param name="numberOfFrames">Number of frames contained inthe sprite sheet</param>
        /// <param name="direction">Direction that the frames are distributed</param>
        public AnimatedSprite(Texture2D spriteSheet, int fps, int numberOfFrames, Direction direction)
        {
            this.spriteSheet = spriteSheet;
            this.fps = fps;
            this.direction = direction;
            if (direction == Direction.Horizontal)
                this.frame = new Rectangle(0, 0, spriteSheet.Width / numberOfFrames, spriteSheet.Height);
            else this.frame = new Rectangle(0, 0, spriteSheet.Width, spriteSheet.Height / numberOfFrames);
        }

        #endregion

        #region Control Methods

        /// <summary>
        /// Plays the animation on a loop
        /// </summary>
        public void Play()
        {
            playing = true;
        }

        /// <summary>
        /// Plays the animation for only one cycle
        /// </summary>
        public void PlayOnce()
        {
            playOnce = true;
        }

        /// <summary>
        /// Stops the Animation when t reaches its end
        /// </summary>
        public void Stop()
        {
            playOnce = false;
            playing = false;
        }

        #endregion

        #region Update and Draw

        /// <summary>
        /// Updates the sprite, countng time and changing frames
        /// </summary>
        /// <param name="gameTime"></param>
        public void Update(GameTime gameTime)
        {
            if (playOnce && !playing)
                playing = true;
            if ((playing || ((frame.X * (1 - (int)direction) != 0) && (frame.Y * (int)direction != 0))) && (elapsedTime > (1.0/fps)))
            {
                frame.X += (1 - (int)direction) * frame.Width;
                frame.Y += (int)direction * frame.Height;
                if (frame.X + frame.Width > spriteSheet.Width)
                {
                    frame.X = 0;
                    if (playOnce && playing)
                        playOnce = playing = false;
                }
                if (frame.Y + frame.Height > spriteSheet.Height)
                {
                    frame.Y = 0;
                    if (playOnce && playing)
                        playOnce = playing = false;
                }
                elapsedTime = 0;
            }
            elapsedTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
        }

        /// <summary>
        /// Draws the current frame
        /// </summary>
        /// <param name="spriteBatch">spriteBatch used to draw the sprites</param>
        /// <param name="pos">Position on the screen</param>
        /// <param name="color">Color to tint the sprite. Use Color.White for no tinting</param>
        public void Draw(SpriteBatch spriteBatch, Vector2 pos, Color color)
        {
            spriteBatch.Draw(spriteSheet, pos, frame, color);
        }

        #endregion
    }
}
